package net.gdface.service.sdk;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import net.gdface.cli.ThriftServiceConfig;
import net.gdface.sdk.ContextLoader;
import net.gdface.sdk.FaceApi;
import net.gdface.sdk.FaceApiContext;
import net.gdface.sdk.ContextLoader.GlobalContextField;
import net.gdface.utils.ReflectionUtils;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;;

/**
 * 服务配置参数
 * @author guyadong
 *
 */
public class FaceApiServiceConfig extends ThriftServiceConfig implements FaceApiServiceConstants {
	private FaceApi faceapi;
	private int xhrPort;
	private int restfulPort;
	private boolean xhrStart;
	private boolean restfulStart;
	private boolean swaggerEnable = true;
	private boolean corsEnable = true;
	private int faceapiConcurrency;
	private static final  FaceApiServiceConfig INSTANCE = new FaceApiServiceConfig();
	public FaceApiServiceConfig() {
		super(DEFAULT_PORT);
		options.addOption(Option.builder().longOpt(FACEAPI_CLASS_OPTION_LONG)
				.desc(FACEAPI_CLASS_OPTION_DESC).numberOfArgs(1).build());
		options.addOption(Option.builder().longOpt(FACEAPI_STATIC_OPTION_LONG)
				.desc(FACEAPI_STATIC_OPTION_DESC).numberOfArgs(1).build());
		options.addOption(Option.builder(FACEAPI_CONCURRENCY_OPTION).longOpt(FACEAPI_CONCURRENCY_OPTION_LONG)
				.desc(FACEAPI_CONCURRENCY_OPTION_DESC).numberOfArgs(1).type(Number.class).build());

		options.addOption(Option.builder(FACEAPI_XHR_OPTION).longOpt(FACEAPI_XHR_OPTION_LONG)
				.desc(FACEAPI_XHR_OPTION_DESC + DEFAULT_PORT_XHR).numberOfArgs(1).type(Number.class).build());
		options.addOption(Option.builder(FACEAPI_XHR_START_OPTION).longOpt(FACEAPI_XHR_START_OPTION_LONG)
				.desc(FACEAPI_XHR_START_OPTION_DESC).numberOfArgs(0).build());
		options.addOption(Option.builder(FACEAPI_RESTFUL_OPTION).longOpt(FACEAPI_RESTFUL_OPTION_LONG)
				.desc(FACEAPI_RESTFUL_OPTION_DESC + DEFAULT_PORT_RESTFUL).numberOfArgs(1).type(Number.class).build());
		options.addOption(Option.builder(FACEAPI_RESTFUL_START_OPTION).longOpt(FACEAPI_RESTFUL_START_OPTION_LONG)
				.desc(FACEAPI_RESTFUL_START_OPTION_DESC).numberOfArgs(0).build());
		options.addOption(Option.builder(FACEAPI_SWAGGER_ENABLE_OPTION).longOpt(FACEAPI_SWAGGER_ENABLE_OPTION_LONG)
				.desc(FACEAPI_SWAGGER_ENABLE_OPTION_DESC).numberOfArgs(0).build());
		options.addOption(Option.builder(FACEAPI_CORS_ENABLE_OPTION).longOpt(FACEAPI_CORS_ENABLE_OPTION_LONG)
				.desc(FACEAPI_CORS_ENABLE_OPTION_DESC).numberOfArgs(0).build());
		
		defaultValue.setProperty(FACEAPI_CLASS_OPTION_LONG,"");
		defaultValue.setProperty(FACEAPI_STATIC_OPTION_LONG,DEFAULT_STATIC_METHOD);
		defaultValue.setProperty(FACEAPI_CONCURRENCY_OPTION_LONG,Runtime.getRuntime().availableProcessors());
		defaultValue.setProperty(FACEAPI_XHR_OPTION_LONG,DEFAULT_PORT_XHR);
		defaultValue.setProperty(FACEAPI_XHR_START_OPTION_LONG,false);
		defaultValue.setProperty(FACEAPI_RESTFUL_OPTION_LONG,DEFAULT_PORT_RESTFUL);
		defaultValue.setProperty(FACEAPI_RESTFUL_START_OPTION_LONG,false);
		defaultValue.setProperty(FACEAPI_SWAGGER_ENABLE_OPTION_LONG,true);	
		defaultValue.setProperty(FACEAPI_CORS_ENABLE_OPTION_LONG,true);
	}

	@Override
	public void loadConfig(Options options, CommandLine cmd) throws ParseException {
		super.loadConfig(options, cmd);
		this.faceapiConcurrency = ((Number)getProperty(FACEAPI_CONCURRENCY_OPTION_LONG)).intValue();
		this.faceapi = getFaceApiInstance();
		this.xhrStart = (Boolean)getProperty(FACEAPI_XHR_START_OPTION_LONG);
		this.xhrPort = ((Number)getProperty(FACEAPI_XHR_OPTION_LONG)).intValue();
		this.restfulStart = (Boolean)getProperty(FACEAPI_RESTFUL_START_OPTION_LONG);
		this.restfulPort = ((Number)getProperty(FACEAPI_RESTFUL_OPTION_LONG)).intValue();
		this.swaggerEnable = (Boolean)getProperty(FACEAPI_SWAGGER_ENABLE_OPTION_LONG);
		this.corsEnable = (Boolean)getProperty(FACEAPI_CORS_ENABLE_OPTION_LONG);
	}
	/**
	 * 返回{@link FaceApi}实例<br>
	 * 如果定义了命令行参数 {@link FaceApiServiceConstants#FACEAPI_CLASS_OPTION_LONG}则从该参数获取{@link FaceApi}实例<br>
	 * 否则尝试从从SPI加载的上下文实例({@link FaceApiContext})中获取获取{@link FaceApi}实例,获取不到则抛出异常
	 * @return {@link FaceApi}实例
	 */
	private FaceApi getFaceApiInstance(){
		// 设置并发线程数
		ContextLoader.setGlobalContext(GlobalContextField.CONCURRENCY, faceapiConcurrency);
		logger.info(String.format("FaceApi concurrency capcaity(SDK并发):%s",faceapiConcurrency));
		String clazzName = (String)getProperty(FACEAPI_CLASS_OPTION_LONG);
		if(Strings.isNullOrEmpty(clazzName)){
			FaceApiContext context = ContextLoader.getInstance().getContext();
			checkArgument(context != null,
					"NOT FOUND FaceApiContext instance,NOT define option %s",
					FACEAPI_CLASS_OPTION_LONG);
			return (FaceApi) checkNotNull(context.getContext().get(ContextLoader.ContextField.INSTANCE),"NOT DEFINE FaceApi Instance in context");
		}
		ImmutableMap<String, Object> params = ImmutableMap.<String, Object>of(ReflectionUtils.PROP_CLASSNAME, clazzName, 
				ReflectionUtils.PROP_STATICMETHODNAME, (String)getProperty(FACEAPI_STATIC_OPTION_LONG));
		try {
			return ReflectionUtils.getInstance(FaceApi.class, params);
		} catch (Exception e) {
			Throwables.throwIfUnchecked(e);
			throw new RuntimeException(e);
		}
	}
	@Override
	protected String getAppName() {
		return FaceApiServiceMain.class.getName();
	}

	public static FaceApiServiceConfig getInstance() {
		return INSTANCE;
	}

	public FaceApi getFaceapi() {
		return faceapi;
	}

	/**
	 * @return xhrPort
	 */
	public int getXhrPort() {
		return xhrPort;
	}

	/**
	 * @return restfulPort
	 */
	public int getRestfulPort() {
		return restfulPort;
	}

	/**
	 * @return xhrStart
	 */
	public boolean isXhrStart() {
		return xhrStart;
	}

	/**
	 * @return restfulStart
	 */
	public boolean isRestfulStart() {
		return restfulStart;
	}

	public boolean isSwaggerEnable() {
		return swaggerEnable;
	}

	public boolean isCorsEnable() {
		return corsEnable;
	}

	public void setCorsEnable(boolean corsEnable) {
		this.corsEnable = corsEnable;
	}
	
}
